package mbp.agents;

import java.io.File;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;

import mbp.base.MessageType;
import mbp.base.Settings;
import mbp.core.CounterOffer;
import mbp.core.Intention;
import mbp.core.JarFolder;
import mbp.core.Offer;
import mbp.core.Resource;
import mbp.core.ResourceUtility;
import mbp.core.ResourceValidation;
import mbp.core.Service;
import mbp.gui.frames.MbpManagerGui;
import mbp.logger.LoggerProxy;
import mbp.message.Message;
import mbp.message.MessageXml;
import mbp.message.contract;
import mbp.message.extra;
import mbp.message.resource;
import mbp.message.utility;
import mbp.recorder.AgentRecorder;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.OntologyException;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.JADEAgentManagement.JADEManagementOntology;
import jade.domain.JADEAgentManagement.SniffOn;
import jade.lang.acl.ACLMessage;
import jade.tools.sniffer.Sniffer;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.StaleProxyException;

/**
 * Agent Manager systemu MBP. Implementuje funkcje przegladania systemu i zarzadzania agentami
 * @author Wojciech Wilanski
 *
 */
public class MbpManagerAgent  extends Agent
{
	MbpManagerGui frame;
	MbpManagerAgent mbpManager;
	Logger logger;
	
	private AgentRecorder agentRecorder;
	private boolean recording;
	
	@Override
	protected void setup()
	{
		//Ustawienie parametrow loggera
		JarFolder jf = new JarFolder();
		PropertyConfigurator.configure(jf.getJarFolder() + "conf" + File.separatorChar + "log4j.properties");
		logger = Logger.getLogger(this.getClass());
		logger.info("\n-----------------------------------------------------------------------------------");
		
		mbpManager = this;
		
		ProcessMassage processMessage = new ProcessMassage();
		addBehaviour(processMessage);
		
		
		try 
		{
			frame = new MbpManagerGui(this);
			frame.setVisible(true);
		} 
		catch (Exception e) 
		{
			logger.error("Exception", e);
		}
		
		agentRecorder = new AgentRecorder();
		recording = false;
		
		Settings.managerName = getLocalName();
		Settings.loadSettings();
		
		startMbpPlatform();
		
		logger.info("Agent " + getAID().getName() + " is ready.");
		
	}
	
	public void startMbpPlatform()
	{
		if(Settings.isSniffer) {
			StartAgent("jade.tools.sniffer.Sniffer", Settings.snifferName, new Object[]{getName()});
		}
		
		
		//uruchomienie agenta rejestru uslug
		StartAgent("mbp.agents.MbpRegisterAgent", Settings.registerName, null);
		
		//uruchomienie agenta magazyn zasobow
		StartAgent("mbp.agents.MbpStorageAgent", Settings.storageName, null);
		
		try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		if(Settings.isSniffer && Settings.sniffRegister) {
			addAgentToSniffer(Settings.registerName);
		}
		
		if(Settings.isSniffer && Settings.sniffStorage) {
			addAgentToSniffer(Settings.storageName);
		}
	}
	
	public void addAgentToSniffer(String agentName)
	{
		String snifferName = Settings.snifferName;
		SniffOn agact = new SniffOn();
		agact.addSniffedAgents(new AID(agentName, AID.ISLOCALNAME));
		agact.setSniffer(new AID(snifferName, AID.ISLOCALNAME));
		
		ACLMessage msg=new ACLMessage(ACLMessage.REQUEST);
		msg.setLanguage(new SLCodec().getName());
		msg.setOntology(JADEManagementOntology.getInstance().getName());
		getContentManager().registerLanguage(new SLCodec());
		getContentManager().registerOntology(JADEManagementOntology.getInstance());

		Action act=new Action(new AID(snifferName, AID.ISLOCALNAME),agact);
		try {
			getContentManager().fillContent(msg,act);
		} catch (CodecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (OntologyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		msg.addReceiver(new AID(snifferName, AID.ISLOCALNAME));
		SenderLogger.send(this, msg);
	}
	
	
	public class ProcessMassage extends CyclicBehaviour
	{

		@Override
		public void action() 
		{
			ACLMessage msg = myAgent.receive();
			
			if(msg!=null)
			{
				LoggerProxy.logReceiving(msg, myAgent);

				//System.out.println("MbpManager Recieved: From " + msg.getSender().getName());
				logger.info("Recieved message from " + msg.getSender().getName());
				logger.debug(msg.toString());
				
				Message iMsg = new Message(msg);
				if(iMsg.isValid())
				{
					MessageType messageType = iMsg.getMessageType();
					switch(messageType)
					{
					case RESOURCEL:
						frame.resourceViewerGui.reloadResourcesList(iMsg.getContentXml());
						break;
					case RESOURCE:
						//frame.resourceViewerGui.LoadResourceDetails(iMsg.getContentXml());
						frame.resourceViewerGui.loadResource(iMsg.getResource());
						break;
					case UTILITYL:
						frame.resourceViewerGui.reloadUtilityList(iMsg.getContentXml());
						break;
					case UTILITY:
						frame.resourceViewerGui.loadUtility(iMsg.getResourceUtility().get(0));
						break;
					case VALIDATIONL:
						frame.resourceViewerGui.reloadValidationList(iMsg.getContentXml());
						break;
					case VALIDATION:
						frame.resourceViewerGui.loadUtility(iMsg.getResourceUtility().get(0));
						break;
					case SERVICEL:
						frame.serviceViewerGui.reloadServicesList(iMsg.getContentXml());
						break;
					case SERVICE:
						frame.serviceViewerGui.loadService(iMsg.getService());
						break;
					case OFFER:
						Offer offer = iMsg.getOffer();
						frame.serviceServerGui.loadRecievedOffer(offer);
						break;
					case EXTRA:
						onExtra(iMsg, msg.getSender().getLocalName());
						break;
					default:
						logger.warn("Message type: " + messageType + " not supported");
						break;
					}
					
				}
				else
				{
					if(iMsg.isJedeMgm())
					{
						logger.info("JADE-Agent-Management " + msg.getSender().getName() + " : " +
								jade.lang.acl.ACLMessage.getPerformative(msg.getPerformative()));
					}
					else
					{
						logger.error("Message in not valid!");
					}
				}
			}
			else
			{
				block();
			}			
		}	
	}
	
	public void startRecording()
	{
		if(!recording)
		{
			agentRecorder.startRecording();
			recording = true;
		}
	}
	
	public void stopRecording(String fileName)
	{
		if(recording)
		{
			agentRecorder.stopRecording(fileName);
			recording = false;
		}
	}
	
	public void continueRecording(String fileName)
	{
		if(!recording)
		{
			agentRecorder.continueRecording(fileName);
			recording = true;
		}
	}
	
	public void SendObjectLGet(String agentName, MessageType messageType)
	{
//		if(messageType == MessageType.RESOURCELGET)
//		{
//			Message message = new Message(messageType, getLocalName(), agentName);
//			
//			extra ex = new extra();
//			ex.name = "owner";
//			ex.value = "ww";
//			message.getContentXml().extras.add(ex);
//			
//			ACLMessage msg = message.GetACLMessage();		
//			SenderLogger.send(this, msg);
//		}
		
		Message message = new Message(messageType, getLocalName(), agentName);
		ACLMessage msg = message.GetACLMessage();
		
		SenderLogger.send(this, msg);
	}
	
	public void SendResourceGet(String agentName, String type, String uuid)
	{
		Message message = new Message(MessageType.RESOURCEGET, getLocalName(), agentName);
		MessageXml mxml = new MessageXml();
		resource rc = new resource();
		rc.type = type;
		rc.resourceid = uuid;
		mxml.resources.add(rc);
		message.setContentXml(mxml);
		
		ACLMessage msg = message.GetACLMessage();
		
		SenderLogger.send(this, msg);
	}
	
	public void SendUtilityGet(String agentName, String type)
	{
		Message message = new Message(MessageType.UTILITYGET, getLocalName(), agentName);
		utility ut = new utility();
		ut.type = type;
		message.getContentXml().utilities.add(ut);
		ACLMessage msg = message.GetACLMessage();
		
		SenderLogger.send(this, msg);
	}
	
	public void SendServiceGet(String agentName, int index)
	{
		Message message = new Message(MessageType.SERVICEGET, getLocalName(), agentName);
		extra ext = new extra();
		ext.name = "index";
		ext.value = Integer.toString(index);
		message.getContentXml().extras.add(ext);
		ACLMessage msg = message.GetACLMessage();
		SenderLogger.send(this, msg);
	}
	
	public void StartAgent(String agentClass, String agentName, Object[] params)
	{
		AgentContainer ac = getContainerController();
		try 
		{
			AgentController agentToStart = ac.createNewAgent(agentName, agentClass, params);
			agentToStart.start();
			
			//if(Settings.isSniffer)
			//{
			//	addAgentToSniffer(agentName);
			//}
			
			if(recording)agentRecorder.startNewAgent(agentClass, agentName);
		}
		catch (StaleProxyException e) 
		{
			logger.error("StaleProxyException", e);
			frame.ShowErrorWindow( e.toString() );
		}
	}
	
	public void SendResource(Resource resource, String agentName)
	{
		mbp.message.Message iMsg = new mbp.message.Message(MessageType.RESOURCE, this.getLocalName(), agentName);
		iMsg.setResource(resource);
		SenderLogger.send(this, iMsg.GetACLMessage());
		
		if(recording)agentRecorder.sendResourceToAgent(agentName, resource);
	}
	
	public void SendIntention(Intention intention)
	{
		//Object[] args = new Object[3];
		//args[0] = agentName;
		//args[1] = this.getLocalName();
		//args[2] = intention;
		//StartAgent("mbp.agents.MbpBaseAgent", this.getLocalName() + "task1", args);
		String agentName = intention.getServerName();
		intention.setClientName(this.getLocalName());
		Message iMsg = new Message(MessageType.INTENTION, this.getLocalName(), agentName);
		iMsg.setIntention(intention);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	public void SendCounterOffer(CounterOffer coffer, String agentName)
	{
		Message iMsg = new Message(MessageType.COUNTEROFFER, this.getLocalName(), agentName);
		//coffer.setClientName(getLocalName());
		iMsg.setCounterOffer(coffer);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	public void SendResourceUtility(ResourceUtility resourceUtility, String agentName)
	{
		Message iMsg = new Message(MessageType.UTILITY, this.getLocalName(), agentName);
		iMsg.setResourceUtility(resourceUtility);
		SenderLogger.send(this, iMsg.GetACLMessage());
		
		if(recording)agentRecorder.sendUtilityToAgent(agentName, resourceUtility);
	}
	
	public void SendResourceValidation(ResourceValidation resourceValidation, String agentName)
	{
		Message iMsg = new Message(MessageType.VALIDATION, this.getLocalName(), agentName);
		iMsg.setResourceValidation(resourceValidation);
		SenderLogger.send(this, iMsg.GetACLMessage());
		
		if(recording)agentRecorder.sendValidationToAgent(agentName, resourceValidation);
	}
	
	public void SendService(Service service, String agentName)
	{
		Message iMsg = new Message(MessageType.SERVICE, this.getLocalName(), agentName);
		iMsg.setService(service);
		SenderLogger.send(this, iMsg.GetACLMessage());
		
		if(recording)agentRecorder.sendServiceToAgent(agentName, service);
	}
	
	public void SendAcceptOffer(Offer offer, String agentName)
	{
		Message iMsg = new Message(MessageType.ACCEPTOFFER, this.getLocalName(), agentName);
		iMsg.setOffer(offer);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	public void sendDoDelete(String agentName)
	{
		Message iMsg = new Message(MessageType.DODELETE, this.getLocalName(), agentName);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	//Metody testowe
	public void startClientAgent(Object[] args)
	{
		String agentClass = "mbp.agents.MbpClientAgent";
		String agentName = "client1";
		StartAgent(agentClass, agentName, args);
	}
	
	public void sendExtra(extra ex, String agentName)
	{
		Message iMsg = new Message(MessageType.EXTRA, this.getLocalName(), agentName);
		iMsg.getContentXml().extras.add(ex);
		SenderLogger.send(this, iMsg.GetACLMessage());
	}
	
	public void onExtra(mbp.message.Message iMsg, String senderName)
	{
		extra ex = iMsg.getContentXml().extras.get(0);
		
		if(ex.name.compareTo("message")==0)
		{
			frame.ShowErrorWindow(ex.value);
			return;
		}
		
		if(ex.name.compareTo("contract")==0)
		{
			if(senderName.compareTo(frame.businessAgentGuiExpl.getActiveAgent())==0)
			{
				List<contract> cntriList = iMsg.getContentXml().contracts;
				frame.businessAgentGuiExpl.reloadContracts(cntriList);
			}
		}
	}

}
